using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using BaseTreeList = DevExpress.XtraTreeList;
using System.Drawing;
using THSLib;
using THSERP.BusinessEntities;
using System.Data;
namespace THSERP.BaseProvider
{
    public class THSTreeList: THSList<THSTreeListObject>, BaseTreeList.TreeList.IVirtualTreeListData
    {
        #region Variables
        protected THSTreeListControl _treeListControl;
        protected bool CheckAll;
        protected String _name;
        protected String _tag;
        protected Size _size;
        protected Point _location;
        protected int _tabIndex;
        #endregion

        #region Public properties
        public String Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }
        public String Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
        public Size Size
        {
            get { return _size; }
            set { _size = value; }
        }
        public Point Location
        {
            get { return _location; }
            set { _location = value; }
        }
        public int TabIndex
        {
            get { return _tabIndex; }
            set { _tabIndex = value; }
        }
        public THSTreeListControl TreeListControl
        {
            get
            {
                return _treeListControl;
            }
            set
            {
                _treeListControl = value;
            }
        }

        public THSTreeListObject CurrentObject
        {
            get
            {
                BaseTreeList.Nodes.TreeListNode currentNode = TreeListControl.GetSelectedNode();
                if (currentNode != null)
                    return (THSTreeListObject)TreeListControl.GetDataRecordByNode(currentNode);
                return null;
            }
            set
            {
                BaseTreeList.Nodes.TreeListNode currentNode = TreeListControl.GetSelectedNode();
                if (currentNode != null)
                {
                    THSTreeListObject currentObject = (THSTreeListObject)TreeListControl.GetDataRecordByNode(currentNode);
                    currentObject = value;
                }
            }
        }
        #endregion

        void BaseTreeList.TreeList.IVirtualTreeListData.VirtualTreeGetChildNodes(BaseTreeList.VirtualTreeGetChildNodesInfo info)
        {
            THSTreeListObject obj = info.Node as THSTreeListObject;
            info.Children = obj.SubList;
        }

        void BaseTreeList.TreeList.IVirtualTreeListData.VirtualTreeGetCellValue(BaseTreeList.VirtualTreeGetCellValueInfo info)
        {
           
            THSTreeListObject obj = info.Node as THSTreeListObject;
            info.CellData = THSDbUtil.GetPropertyValue(obj, info.Column.FieldName);
        }
        void BaseTreeList.TreeList.IVirtualTreeListData.VirtualTreeSetCellValue(BaseTreeList.VirtualTreeSetCellValueInfo info)
        {
           
            THSTreeListObject obj = info.Node as THSTreeListObject;
            THSDbUtil.SetPropertyValue(obj, info.Column.FieldName, info.NewCellData);
        }

        public virtual void InitTHSTreeListControl()
        {
            String strTreeListControlName = "fld_trl" + ItemTableName;
            InitTHSTreeListControl(strTreeListControlName);
        }

        public virtual void InitTHSTreeListControl(String strTreeListControlName)
        {
            if (Entity.Module.Controls[strTreeListControlName] != null)
            {
                TreeListControl = Entity.Module.Controls[strTreeListControlName] as THSTreeListControl;
                TreeListControl.FocusedNodeChanged += new BaseTreeList.FocusedNodeChangedEventHandler(TreeList_FocusedNodeChanged);
                //hieu.nguyen remove 10/08/2011 reason excute 2 times key up on gridcontrol
                //TreeListControl.KeyUp += new KeyEventHandler(TreeList_KeyUp);
                TreeListControl.CellValueChanging += new BaseTreeList.CellValueChangedEventHandler(TreeList_CellValueChanging);
            }
        }

        public void SetDefaultListAndRefreshTreeListControl()
        {
            this.Clear();
            this.OriginalList.Clear();
            if (TreeListControl != null)
                TreeListControl.RefreshDataSource();
        }

        #region Tree list event handlers
        protected virtual void TreeList_FocusedNodeChanged(object sender, BaseTreeList.FocusedNodeChangedEventArgs e)
        {
            if (e.Node != null)
            {
                String strMainTableName = String.Empty;
                if (Entity.MainObject != null)
                    strMainTableName = THSUtil.GetTableNameFromBusinessObject(Entity.MainObject);
                if (ItemTableName.Equals(strMainTableName))
                {
                    Entity.MainObject = (BusinessObject)CurrentObject.Clone();
                    Entity.UpdateMainObjectBindingSource();
                }
                else
                    Entity.InvalidateModuleObject((BusinessObject)CurrentObject.Clone());
            }
        }
        //hieu.nguyen remove 10/08/2011 reason excute 2 times key up on gridcontrol
        //protected virtual void TreeList_KeyUp(object sender, KeyEventArgs e)
        //{
        //    if (e.KeyCode == Keys.Delete)
        //        RemoveSelectedRowObjectFromList();
        //}

        protected virtual void TreeList_CellValueChanging(object sender, BaseTreeList.CellValueChangedEventArgs e)
       {
            if (Entity.Module.Toolbar.IsNullOrNoneAction())
            {
                if (Entity.ModuleObjects[ItemTableName] != null && Entity.ModuleObjects[ItemTableName].AllowPropertyChangedEvent)
                    Entity.Module.ActionEdit();
            }
        }
        #endregion

        #region Invalidation functions
        public virtual void InvalidateTreeList(int iObjectID)
        {
            CheckAll = false;
            this.Invalidate(iObjectID);

            if (TreeListControl != null)
            {
                if (this.Count > 0)
                    Entity.InvalidateModuleObject(this[0]);
                else
                    Entity.InvalidateModuleObject(BusinessObjectFactory.GetBusinessObject(ItemTableName + "Info"));
                TreeListControl.RefreshDataSource();
                TreeListControl.ExpandAll();
            }
        }

        public virtual void InvalidateTreeList(int iObjectID, bool checkAll)
        {
            CheckAll = checkAll;
            this.Invalidate(iObjectID);
            if (TreeListControl != null)
            {
                if (this.Count > 0)
                    Entity.InvalidateModuleObject(this[0]);
                else
                    Entity.InvalidateModuleObject(BusinessObjectFactory.GetBusinessObject(ItemTableName + "Info"));
                TreeListControl.RefreshDataSource();
                TreeListControl.ExpandAll();
            }
        }

        public override void Invalidate(int iObjectID)
        {
            base.Invalidate(iObjectID);

           
            foreach (THSTreeListObject obj in this)
            {
                if (CheckAll)
                    obj.Selected = true;
                
                //Make the type of sub list be same as its parent
                object objType = this.GetType().InvokeMember("", BindingFlags.CreateInstance, null, null, null);
                obj.SubList = (THSTreeList)objType;
                obj.SubList.InitTHSList(Entity, ItemTableName, ItemTableName);

                String parentTablePrimaryKey = THSDbUtil.GetTablePrimaryColumn(obj.SubList.ParentTableName);
                int parentObjectID = Convert.ToInt32(THSDbUtil.GetPropertyValue(obj, parentTablePrimaryKey));
                obj.SubList.CheckAll = CheckAll;
                obj.SubList.Invalidate(parentObjectID);
                foreach (THSTreeListObject objSub in obj.SubList)
                    objSub.Parent = obj;
            }
        }

       
        public virtual void InvalidateTreeList(DataSet ds, bool checkAll,THSTreeListControl treeList )
        {
            CheckAll = checkAll;
            TreeListControl = treeList;
           // this.Invalidate(ds);
            List<THSTreeListObject> list = new List<THSTreeListObject>();
            if (TreeListControl != null)
            {
                
                BusinessObject rowObj = BusinessObjectFactory.GetBusinessObject(ItemTableName + "Info");
                BaseBusinessController controller = BusinessControllerFactory.GetBusinessController(ItemTableName + "Controller");
                foreach (DataRow row  in ds.Tables[0].Rows)
                {

                    rowObj = (BusinessObject)controller.GetObjectFromDataRow(row);
                    String parentTablePrimaryKey = THSDbUtil.GetTablePrimaryColumn(ItemTableName);
                    int parentObjectID = Convert.ToInt32(THSDbUtil.GetPropertyValue(rowObj, parentTablePrimaryKey));
                    int childID = Convert.ToInt32(THSDbUtil.GetPropertyValue(rowObj, ItemTableName.Substring(0, ItemTableName.Length - 1) + "ParentID"));
                    if (childID == 0)
                    {
                        THSTreeListObject obj = new THSTreeListObject();
                        if (CheckAll)
                            obj.Selected = true;
                        obj = (THSTreeListObject)rowObj;
                        //Make the type of sub list be same as its parent
                        object objType = this.GetType().InvokeMember("", BindingFlags.CreateInstance, null, null, null);
                        obj.SubList = (THSTreeList)objType;
                        obj.SubList.InitTHSList(Entity, ItemTableName, ItemTableName);
                        obj.SubList.CheckAll = CheckAll;
                        obj.SubList.Invalidate(parentObjectID);
                        foreach (THSTreeListObject objSub in obj.SubList)
                            objSub.Parent = obj;
                        list.Add(obj);
                    }
                }
                TreeListControl.ExpandAll();
            }
            this.Invalidate(list);
        }

        #endregion 

        public override THSTreeListObject SaveObjectToList(bool IsNew)
        {
            if (TreeListControl != null)
                TreeListControl.InvalidateLookupEditColumns();

           
            String strMainTableName = String.Empty;
            if (Entity.MainObject != null)
                strMainTableName = THSUtil.GetTableNameFromBusinessObject(Entity.MainObject);

            THSTreeListObject obj = new THSTreeListObject();
            if (!String.IsNullOrEmpty(ParentTableName))
            {
                if (ItemTableName.Equals(strMainTableName))
                {
                    obj = (THSTreeListObject)Entity.MainObject.Clone();
                }
                else
                {
                    obj = (THSTreeListObject)Entity.ModuleObjects[ItemTableName].Clone();
                }
            }
            else
            {
                obj = (THSTreeListObject)Entity.ModuleObjects[ItemTableName].Clone();
            }
            //Refer sub list to new list because Clone() does not copy it
            obj.SubList = new THSTreeList();

            if (IsNew)
            {
                String strPrimaryKey = ItemTableName.Substring(0, ItemTableName.Length - 1) + "ID";
                THSDbUtil.SetPropertyValue(obj, strPrimaryKey, 0);
                CurrentObject.SubList.Add(obj);
            }
            else
            {
                THSTreeListObject currObj = CurrentObject;
                PropertyInfo[] props = currObj.GetType().GetProperties();
                foreach (PropertyInfo prop in props)
                    if (typeof(THSTreeListObject).GetProperty(prop.Name) == null)
                        THSDbUtil.SetPropertyValue(currObj, prop.Name, THSDbUtil.GetPropertyValue(obj, prop.Name));
            }
            return obj;
        }

        public override void AddObjectToList()
        {
            if (CurrentObject != null)
            {
                this.SaveObjectToList(true);
                TreeListControl.RefreshDataSource();
                TreeListControl.ExpandAll();
            }
        }

        public override void ChangeObjectFromList()
        {
            BaseTreeList.Nodes.TreeListNode currNode = TreeListControl.GetSelectedNode();
            if (currNode != null)
            {
                if (TreeListControl.THSDisplayRoot && currNode.Level == 0)
                    return;
                this.SaveObjectToList(false);
                TreeListControl.RefreshDataSource();
                TreeListControl.ExpandAll();
            }
        }

        public override void RemoveSelectedRowObjectFromList()
        {
            BaseTreeList.Nodes.TreeListNode currentNode = TreeListControl.GetSelectedNode();
            if (currentNode != null)
            {
                if (TreeListControl.THSDisplayRoot)
                {
                    if (currentNode.Level > 0)
                        currentNode.ParentNode.Nodes.Remove(currentNode);
                }
                else
                {
                    if (currentNode.Level == 0)
                        TreeListControl.Nodes.Remove(currentNode);
                    else
                        currentNode.ParentNode.Nodes.Remove(currentNode);
                }
            }
        }

        public override void SaveItemObjects()
        {
            EndCurrentEdit();

            base.SaveItemObjects();

           
            foreach (THSTreeListObject obj in this)
            {
                obj.SubList.InitTHSList(Entity, ItemTableName, ItemTableName);
                String parentTablePrimaryKey = THSDbUtil.GetTablePrimaryColumn(obj.SubList.ParentTableName);
                int parentObjectID = Convert.ToInt32(THSDbUtil.GetPropertyValue(obj, parentTablePrimaryKey));
                foreach (THSTreeListObject objSub in obj.SubList)
                {
                    THSDbUtil.SetPropertyValue(objSub, obj.SubList.ItemTableForeignKey, parentObjectID);
                }
                if (obj.SubList.Count > 0 || obj.SubList.OriginalList.Count > 0)
                    obj.SubList.SaveItemObjects();
            }
        }

        #region Functions for getting object
        public virtual THSTreeListObject GetSelectedObject()
        {
            foreach (THSTreeListObject obj in this)
            {
                if (obj.Selected)
                    return obj;
                if (obj.HasChildren())
                {
                    THSTreeListObject objSub = obj.SubList.GetSelectedObject();
                    if (objSub != null)
                        return objSub;
                }
            }
            return null;
        }

        public override bool Exists(string strPropertyName, object objPropertyValue)
        {
            THSTreeListObject obj = GetObjectByPropertyNameAndValue(strPropertyName, objPropertyValue);
            if (obj != null)
                return true;
            return false;
        }

        public virtual THSTreeListObject GetObjectByPropertyNameAndValue(string strPropertyName, object objPropertyValue)
        {
            int pos = base.PosOf(strPropertyName, objPropertyValue);
            if (pos >= 0)
                return this[pos];
            else
            {
                foreach (THSTreeListObject obj in this)
                    if (obj.SubList.Count > 0)
                    {
                        THSTreeListObject objSub = obj.SubList.GetObjectByPropertyNameAndValue(strPropertyName, objPropertyValue);
                        if (objSub != null)
                            return objSub;
                    }
            }
            return null;
        }

        public virtual THSTreeListObject GetObjectByTemplateObject(THSTreeListObject objTemplateObject, params String[] propertyNames)
        {
           
            foreach (THSTreeListObject obj in this)
            {
                bool flag = false;
                foreach (String propertyName in propertyNames)
                    if (!THSDbUtil.GetPropertyValue(obj, propertyName).Equals(THSDbUtil.GetPropertyValue(objTemplateObject, propertyName)))
                        flag = true;
                if (flag == false)
                    return obj;
            }

            foreach (THSTreeListObject obj in this)
                if (obj.SubList.Count > 0)
                {
                    THSTreeListObject objSub = obj.SubList.GetObjectByTemplateObject(objTemplateObject, propertyNames);
                    if (objSub != null)
                        return objSub;
                }
            return null;
        }
        #endregion

        public override void Duplicate()
        {
            base.Duplicate();

            foreach (THSTreeListObject obj in this)
                if (obj.HasChildren())
                    obj.SubList.Duplicate();
        }

        public virtual void GetLastNodes(THSList<THSTreeListObject> lst)
        {
            foreach (THSTreeListObject obj in this)
            {
                if (obj.HasChildren())
                    obj.SubList.GetLastNodes(lst);
                else
                    lst.Add(obj);
            }
        }

        public virtual void EndCurrentEdit()
        {
            if (TreeListControl != null)
                TreeListControl.FocusedNode = null;
        }
    }

    public class THSTreeListObject : BusinessObject
    {
        #region Variables
        protected THSTreeListObject _parent;
        protected THSTreeList _subList = new THSTreeList();
        protected bool _selected = false;
        #endregion

        #region Public properties
        public THSTreeListObject Parent
        {
            get
            {
                return _parent;
            }
            set
            {
                _parent = value;
            }
        }

        public THSTreeList SubList
        {
            get
            {
                return _subList;
            }
            set
            {
                _subList = value;
            }
        }

        public bool Selected
        {
            get
            {
                return _selected;
            }
            set
            {
                _selected = value;
            }
        }
        #endregion

        public bool HasChildren()
        {
            if (this.SubList.Count > 0)
                return true;
            return false;
        }

        public bool HasSelectedChildren()
        {
            foreach (THSTreeListObject obj in this.SubList)
            {
                if (obj.HasChildren() == false && obj.Selected)
                    return true;
                else
                {
                    bool result = obj.HasSelectedChildren();
                    if (result)
                        return true;
                }
            }
            return false;
        }
    }
}
